# Copyright (C) 2005-2006 Frederic Back <fredericback@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.

import gtk
import cairo

from _symbol import SymbolRenderer
from _options import Options
from _geodata import ResultSet, Layer
from _guitools import createTreeview, createLabel, createButton
from _queryeditor import QueryEditor
from _guiwindows import *

def createLayerIcon( layer, width=24, height=16, geometryType = None ):
    """ Create a pixbuf from the layer style.
        layer must be a Layer instance. 
        Returns a gtk.Pixbuf """

    if geometryType is None: geometryType = layer.geometryType
    if geometryType is None: return

    pixmap = gtk.gdk.Pixmap(None,width,height,24)
    ctx = pixmap.cairo_create()
  
    # clear area
    ctx.rectangle(0,0,width,height)
    ctx.set_source_rgb(1,1,1)
    ctx.fill()

    if geometryType == "line":
        m = 4 # add a small border, looks much better
        ctx.move_to(m,m);
        ctx.line_to(width/3, height-m)
        ctx.line_to((width/3)*2, m)
        ctx.line_to(width-m, height-m)
        ctx.set_line_width(layer.style.linewidth)
        ctx.set_source_rgba(*layer.style.line.asCairoRGBA())
        ctx.stroke()
    elif geometryType == "point":
        ctx.translate(width/2,height/2)
        ctx.set_line_cap(cairo.LINE_CAP_SQUARE)

        symbol = SymbolRenderer() 
        symbol.recreate(layer.style.line,
            layer.style.outline, layer.style.fill,
            layer.style.symbol,layer.style.symbolsize)
        symbol.render(ctx)

    else:
        ctx.move_to(0, 0)
        ctx.line_to(width, 0)
        ctx.line_to(width, height)
        ctx.line_to(0, height)
        ctx.line_to(0,0)
        ctx.set_source_rgba(*layer.style.fill.asCairoRGBA())
        ctx.fill_preserve()
        ctx.set_line_width(layer.style.linewidth)
        ctx.set_source_rgba(*layer.style.outline.asCairoRGBA())
        ctx.stroke()

    pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,width,height)
    pixbuf.get_from_drawable(pixmap,pixmap.get_colormap(),0,0,0,0,width, height)
    return pixbuf

    # Old version worked by creating xpms
    #def convertColour( gdkcolour ):
        #""" convert to "00FF7F" """
        #colour = ""
        #for i in (gdkcolour.red,gdkcolour.green,gdkcolour.blue):
            #x = "%X" % int(float(i)/65535.0*255)
            #if len(x) == 1: x = "0"+x
            #colour += x
        #return colour
    #border = round(layer.lineWidth)
    #xpm = ["%i %i 2 1" %(width, height),
    #        ".\tc #"+convertColour(layer.colourFill),
    #        "+\tc #"+convertColour(layer.colourLine)]
    #for y in range( height ):
    #    row = ""
    #    for x in range( width ):
    #        if y < border or y >= height-border or x < border or x >= width-border: row += "+"
    #        else: row += "."
    #    xpm.append(row)
    #return gtk.gdk.pixbuf_new_from_xpm_data(xpm)


#--------------------------------------------------------------------------------------------------
def resultProperties(widget, result):
    """ Popup a window to set Result (i.e. map) attributes. """

    dialog = gtk.Dialog(_('Map Properties'),
        widget.get_toplevel(), gtk.DIALOG_DESTROY_WITH_PARENT,
        (gtk.STOCK_CLOSE,0,gtk.STOCK_APPLY,1))

    box = gtk.HBox()
    box.pack_start(createLabel(_("Name: ")),False)
    nameentry = gtk.Entry()
    nameentry.set_text(result.name)
    box.pack_start(nameentry)
    dialog.vbox.pack_start(box)
    dialog.vbox.show_all()

    r = 1
    while r == 1:
        r = dialog.run()
        if r == 1: # apply
            if result.name != nameentry.get_text():
                result.name = nameentry.get_text()
                result.emit("values-changed")

    dialog.destroy()

#--------------------------------------------------------------------------------------------------
def openLayerProperties(layer):
    for i in LayerProperties.instances:
        if i.layer == layer:
            i.present()
            return
    LayerProperties.instances.append(LayerProperties(layer))

class LayerProperties( gtk.Window ):

    instances = []

    def __init__(self, layer):
        gtk.Window.__init__(self)
        self.set_title(_("Layer Properties"))
        self.connect("delete_event",self.close)
        self.layer = layer
        self.vbox = gtk.VBox()
        self.add(self.vbox)

        box = gtk.HBox()
        box.pack_start(createLabel(_("Source SQL: ")),False)
        self.queryentry = gtk.Entry()
        self.queryentry.set_text(layer.query)
        self.queryentry.set_editable(False)
        self.queryentry.set_sensitive(False)
        box.pack_start(self.queryentry)

        b = gtk.Button(None,gtk.STOCK_EDIT)

        self.qe = QueryEditor()
        self.qe.setQuery(self.layer.query)
        self.qe.okButton.connect("clicked",self.__closeEditor)

        b.connect("clicked",self.__showEditor)
        box.pack_start(b,False)

        self.vbox.pack_start(box,False)

        box = gtk.HBox()
        box.pack_start(createLabel(_("Layer Name: ")),False)
        self.nameentry = gtk.Entry()
        self.nameentry.set_text(layer.name)
        box.pack_start(self.nameentry)
        self.vbox.pack_start(box,False)

        self.vbox.pack_start(gtk.HSeparator(),False,False,5)

        notebook = gtk.Notebook()
        notebook.set_size_request(300, 200)
        self.vbox.pack_start(notebook)
    
        #............................................ STYLE
        self.coloursChanged = False

        table = gtk.Table(2,3,False); row = 0
        table.attach(createLabel(_("Line: ")), 0, 1, row, row+1)
        self.line = gtk.ColorButton( layer.style.line.asGdkColor() )
        self.line.set_alpha( int(layer.style.outline.a) )
        self.line.set_use_alpha(True)
        self.line.connect("color-set",self.__setColoursChanged)
        table.attach(self.line, 1, 2, row, row+1); row += 1 # inc

        table.attach(createLabel(_("Outline: ")), 0, 1, row, row+1)
        self.outline = gtk.ColorButton( layer.style.outline.asGdkColor() )
        self.outline.set_alpha( int(layer.style.line.a) )
        self.outline.set_use_alpha(True)
        self.outline.connect("color-set",self.__setColoursChanged)
        table.attach(self.outline, 1, 2, row, row+1); row += 1 # inc

        table.attach(createLabel(_("Fill: ")), 0, 1, row, row+1)
        self.fill = gtk.ColorButton( layer.style.fill.asGdkColor() )
        self.fill.set_alpha( int(layer.style.fill.a) )
        self.fill.set_use_alpha(True)
        self.fill.connect("color-set",self.__setColoursChanged)
        table.attach(self.fill, 1, 2, row, row+1); row += 1 # inc

        table.attach(createLabel(_("Line Width: ")), 0, 1, row, row+1)
        self.lineWidthAdj = gtk.Adjustment(layer.style.linewidth,0,100,0.1,0.5,1)
        borderSpin = gtk.SpinButton(self.lineWidthAdj, 0.1, 1)
        table.attach(borderSpin, 1, 2, row, row+1); row += 1 # inc

        table.attach(createLabel(_("Symbol Size: ")), 0, 1, row, row+1)
        self.symbolSizeAdj = gtk.Adjustment(layer.style.symbolsize,0,100,0.1,0.5,1)
        borderSpin = gtk.SpinButton(self.symbolSizeAdj, 0.1, 1)
        table.attach(borderSpin, 1, 2, row, row+1); row += 1 # inc

        vbox = gtk.VBox()
        vbox.pack_start(table,False)
        notebook.append_page(vbox,gtk.Label("style"))

        #............................................ SYMBOL SELECTION
        vbox = gtk.VBox()
 
        currentSelection = None
        model = gtk.ListStore(str, gtk.gdk.Pixbuf)
        self.iconView = gtk.IconView(model)
        
        self.iconView.set_pixbuf_column(1)
        self.iconView.set_selection_mode(gtk.SELECTION_SINGLE)
        #iconView.connect('selection-changed', on_select)
        self.iconView.set_columns(-1)
        self.iconView.set_item_width(-1)
        self.iconView.set_item_width(-1)

        # Note: I use my own cellTextRenderer, because it seems I cannot access
        # the iconview's celltextrenderer. Fallback for pygtk < 2.8.3
        if gtk.pygtk_version > (2,8,3):
            self.iconView.set_text_column(-1)
            textrenderer = gtk.CellRendererText()
            textrenderer.set_property("scale",0.8)
            textrenderer.set_property("xalign",0.5)
            self.iconView.pack_start(textrenderer,False)
            self.iconView.add_attribute(textrenderer,"markup",0)
        else: self.iconView.set_markup_column(0)

        self.__fillSymbols(model)
        
        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
        sw.add(self.iconView)
        vbox.pack_start(sw)
        notebook.append_page(vbox,gtk.Label(_("symbol")))
        
        #............................................ LABEL

        vbox = gtk.VBox()
        vbox.set_border_width(6)
        
        # add a checkbox
        self.labelFlag = gtk.CheckButton(_("_Display Labels"))
        self.labelFlag.set_active(layer.style.labelFlag)
        vbox.pack_start(self.labelFlag,False)
        
        # add list of columns
        hbox = gtk.HBox()
        hbox.pack_start(gtk.Label(_("Label Column:")),False)        
        self.labelcolumn = gtk.combo_box_new_text()
        if layer.queryDescription is not None:
            for i in range(len(layer.queryDescription)):   
                des = layer.queryDescription[i]
                self.labelcolumn.append_text( str(des[0]) )

        
        if layer.style.labelcolumn is not None:
            self.labelcolumn.set_active(layer.style.labelcolumn)
            
        hbox.pack_start(self.labelcolumn)
        vbox.pack_start(hbox,False)
        
        vbox.pack_start(gtk.HSeparator(),False,False,6)
        
        hbox = gtk.HBox()
        hbox.pack_start(gtk.Label(_("Label Font:")),False)                
        self.labelfont = gtk.FontButton()
        self.labelfont.set_font_name( layer.style.labelfont )
        hbox.pack_start(self.labelfont)
        vbox.pack_start(hbox,False)        
          
        hbox = gtk.HBox()
        hbox.pack_start(gtk.Label(_("Label Colour:")),False)                
        self.labelcolour = gtk.ColorButton( layer.style.labelcolour.asGdkColor() )
        hbox.pack_start(self.labelcolour)
        vbox.pack_start(hbox,False)     
           
        # add syntax entry
        hbox = gtk.HBox()
        vbox.set_border_width(6)
        hbox.pack_start(gtk.Label(_("Label Syntax:")),False)
        self.labelsyntax = gtk.Entry()
        self.labelsyntax.set_text(layer.style.labelsyntax)
        hbox.pack_start(self.labelsyntax)
        vbox.pack_start(hbox,False)
        
        notebook.append_page(vbox,gtk.Label("label"))
        
        #............................................ ADD DIALOGUE BUTTONS
        hbox = gtk.HBox()
        b = gtk.Button(None,gtk.STOCK_APPLY)
        b.connect("clicked",self.__apply)
        hbox.pack_end(b,False)
        b = gtk.Button(None,gtk.STOCK_CLOSE)
        b.connect("clicked",self.close)
        hbox.pack_end(b,False)
        self.vbox.pack_start(hbox,False)

        self.show_all()
        self.present()
        self.nameentry.grab_focus()

    def close(self, w, e=None):
        LayerProperties.instances.remove(self)
        self.destroy()

    def __showEditor(self, widget):
        self.qe.show()

    def __closeEditor(self, widget):
        self.qe.hide()
        query = self.qe.getQuery()
        self.queryentry.set_text( query )

    def __apply(self, w):
        """ "Instant apply" doesn't work in this use case: *Layer* re-rendering! """

        styleChanged = False

        if self.layer.name != self.nameentry.get_text():
            self.layer.name = self.nameentry.get_text()
            self.layer.emit("values-changed")

        if self.layer.style.linewidth != self.lineWidthAdj.get_value():
            self.layer.style.linewidth = self.lineWidthAdj.get_value()
            styleChanged = True

        if self.layer.style.symbolsize != self.symbolSizeAdj.get_value():
            self.layer.style.symbolsize = self.symbolSizeAdj.get_value()
            styleChanged = True

        s = self.iconView.get_selected_items()
        if len(s) > 0: # ugly
            e = s[0][0]
            if e != 0: # 0 = current symbol
                key = SymbolRenderer.commonSymbols.keys()[e-1]
                symbol = SymbolRenderer.commonSymbols[key]
                self.layer.style.symbol = symbol
                styleChanged = True

        if self.coloursChanged:
            c = self.line.get_color(); a = self.line.get_alpha()
            self.layer.style.line.setFromRGBA(c.red,c.green,c.blue,a)

            c = self.outline.get_color(); a = self.outline.get_alpha()
            self.layer.style.outline.setFromRGBA(c.red,c.green,c.blue,a)

            c = self.fill.get_color(); a = self.fill.get_alpha()
            self.layer.style.fill.setFromRGBA(c.red,c.green,c.blue,a)

            self.coloursChanged = False
            styleChanged = True
            
            
        # label.................................
        if self.layer.style.labelFlag != self.labelFlag.get_active():
            self.layer.style.labelFlag = self.labelFlag.get_active()
            styleChanged = True
            
        if self.layer.style.labelcolumn != self.labelcolumn.get_active():
            self.layer.style.labelcolumn = self.labelcolumn.get_active()
            # only redraw if labels are on
            if self.layer.style.labelFlag: styleChanged = True
            
        if self.layer.style.labelsyntax != self.labelsyntax.get_text():
            self.layer.style.labelsyntax = self.labelsyntax.get_text()
            # only redraw if labels are on            
            if self.layer.style.labelFlag: styleChanged = True
    
        if self.layer.style.labelfont != self.labelfont.get_font_name():
            self.layer.style.labelfont = self.labelfont.get_font_name()
            # only redraw if labels are on            
            if self.layer.style.labelFlag: styleChanged = True     
            
        c1 = self.labelcolour.get_color()
        c2 = self.layer.style.labelcolour
        if c1.red != c2.r or c1.green != c2.g or c1.blue != c2.b:
            self.layer.style.labelcolour.setFromRGBA(c1.red,c1.green,c1.blue)
            # only redraw if labels are on            
            if self.layer.style.labelFlag: styleChanged = True       
            
        # other.................................
        if self.layer.query != self.queryentry.get_text():
            self.layer.query = self.queryentry.get_text()
            self.layer.resultset.project.emit("query-changed",self.layer)
            return # NO NEED TO CALL STYLE CHANGED

        if styleChanged:
            self.__fillSymbols( self.iconView.get_model() )
            self.layer.emit("style-changed")

    def __setColoursChanged(self,w):
        self.coloursChanged = True

    def __fillSymbols(self, model):
        model.clear()
        # add current symbol
        renderer = SymbolRenderer()
        renderer.recreate(self.layer.style.line,self.layer.style.outline,
            self.layer.style.fill,self.layer.style.symbol,1.5)
        model.append([_("<i>current symbol</i>"), renderer.renderToPixbuf(32,32) ])
        self.iconView.select_path( (0,) )
        # add common symbols
        for name in SymbolRenderer.commonSymbols:
            symbol = SymbolRenderer.commonSymbols[name]
            renderer.recreate(self.layer.style.line,self.layer.style.outline,
                self.layer.style.fill,
                symbol,1.5)
            model.append(["%s"%name, renderer.renderToPixbuf(32,32) ])


#--------------------------------------------------------------------------------------------------
class LayerView( gtk.VBox ):
    """ A sidepane and methods to manage Results and Layers.
        Layer managment functionality (deleting, etc.) goes here """

    def __init__(self, pgbutler):
        gtk.VBox.__init__(self)
        self.project = None 
        self.pgbutler = pgbutler
        
        self.accelgroup = gtk.AccelGroup()
        self.pgbutler.win.add_accel_group(self.accelgroup)
        
        # TODO: eventually replace this by a proper gtk.Clipboard
        self.clipboardItem = None 

        # create treeview
        # a legend icon, a description, and a percentage (loaded)
        self.model = gtk.TreeStore(gtk.gdk.Pixbuf,str,str)
        self.tv = gtk.TreeView(self.model)
        self.tv.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,[("drag",0,0)], gtk.gdk.ACTION_COPY)
        self.tv.enable_model_drag_dest([("drag",0,0)],gtk.gdk.ACTION_COPY)
        self.tv.connect("drag_data_received", self.__onDragReceived)

        # first column
        crp = gtk.CellRendererPixbuf()
        ctr = gtk.CellRendererText()
        crpercent = gtk.CellRendererText()
        crprogress = gtk.CellRendererProgress()
        
        #ctr.set_property("editable",Options.editableLayerNames)
        #ctr.connect("edited",self.cb_treeEdited)
        col = gtk.TreeViewColumn()
        col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
        col.pack_start(crp, False)
        col.pack_start(ctr, True)
        col.pack_start(crpercent, False)
        col.set_attributes(crp, pixbuf=0)
        col.set_attributes(ctr, text=1)
        col.set_attributes(crpercent, text=2)
        self.tv.append_column(col)

        self.tv.set_headers_visible(False)
        self.tv.connect("button_press_event",self.__onClick)
        #self.tv.connect("popup-menu",lambda w: self.__contextMenu(self.tv.get_cursor()[0]) )
        self.tv.connect("row-activated",self.__onDoubleClick)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)   
        sw.add(self.tv)
        self.pack_start(sw)

    def setProject(self, project):
        self.model.clear()
        self.project = project
        for t in TableWindow.instances + MapWindow.instances: t.close()
        project.connect("resultset-added",self.__onResultAdded)
        project.connect("query-changed",lambda w, l: self.pgbutler.runQuery(l.query,l))

    def getProject(self):
        return self.project

    def reloadLayerDialog(self, widget, layerlist):
        """ Ask the user if he really want's to reload layers.

        mezoGIS xml files contain the SQL queries to recreate a layer. To avoid
        potential malicious behaviour, we ask the user before running reloading
        a layer.
        """
        flag = False
        if Options.askBeforeReloading == True:
            d = gtk.MessageDialog(None,
                gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
                gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO,
                _("Do you really want to perform the following queries?") )
            s = ""
            for layer in layerlist:
                s += str(layer.query) + "\n"
            d.format_secondary_text(s)
            b = gtk.CheckButton(_("Don't ask again"))
            d.vbox.pack_start(b)
            d.show_all()
            r = d.run() 
            if r == gtk.RESPONSE_YES: flag = True
            if b.get_active(): Options.askBeforeReloading = False
            d.destroy()
        else: flag = True
        
        if flag == True: # reload
            for layer in layerlist:
                layer.resultset.project.emit("query-changed",layer)
                
    def __onResultAdded(self, project, result):
        # register callbacks for the result
        result.connect("layer-removed",self.__onLayerRemoved)
        result.connect("layer-added",self.__onLayerAdded)
        result.connect("removed",self.__onResultRemoved)
        result.connect("values-changed",self.__redrawList)

        # register callbacks for the layers
        for layer in result.layers:
            layer.connect("status-changed",self.__onLayerLoading)
            layer.connect("values-changed",self.__onLayerChanged)
            layer.connect("style-changed",self.__onLayerChanged)

        self.__redrawList()

    def __onResultRemoved(self, result):
        self.__redrawList()

    def __redrawList(self, widget = None):
        self.model.clear()
        for result in self.project.resultsets:
            p = self.model.append(None,(None,result.name,None))
            for layer in result.layers:
                self.model.append(p,(createLayerIcon(layer,24,20),layer.name,layer.status))
            self.tv.expand_row(self.model.get_path(p),True)
        self.tv.columns_autosize()


    def __onLayerChanged(self, layer):   
        try:  
            result = layer.resultset
            if result is None: return
            path = "%i:%i" %(self.project.resultsets.index(result),result.layers.index(layer))
            it = self.model.get_iter_from_string(path)
            self.model.set_value(it,1,layer.name)
            self.model.set_value(it,0,createLayerIcon(layer,24,20))
        except Exception, e:
            print "ignore this:"
            print e

    def __onLayerLoading(self, layer, status):
        try:
            result = layer.resultset
            if result is None: return
            path = "%i:%i" %(self.project.resultsets.index(result),result.layers.index(layer))
            it = self.model.get_iter_from_string(path)
            self.model.set_value(it,2,status)
        except Exception, e:
            print "ignore this:"
            print e

    def __onLayerRemoved(self,result,layer):
        print "Layer removed",layer

        # if last layer in resultset, delete resultset            
        if len(result.layers) == 0: self.project.resultsets.remove(result)

        self.__redrawList()

    def __onLayerAdded(self,result,layer):
        layer.connect("status-changed",self.__onLayerLoading)
        layer.connect("values-changed",self.__onLayerChanged)
        layer.connect("style-changed",self.__onLayerChanged)
        self.__redrawList()

    def __onDoubleClick(self, treeview, path, view_column):
        path = self.tv.get_cursor()
        result = self.project.resultsets[ path[0][0] ]
        openMapView( result )


    def __onClick(self, treeview, event):
        if event.button == 3:
            x, y = int(event.x), int(event.y)
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor(path)
                self.__contextMenu(path, event)
            
            
    def __contextMenu(self, path, event):
        """ Note: Context menues are created on the fly because I need the
            option to integrate dynamic content. """
            
        def setClipboardItem(item):
            self.clipboardItem = item

        result = self.project.resultsets[ path[0] ]

        accelgroup = None

        menu = gtk.Menu()
        #menu.set_accel_group(self.accelgroup)
        # clicked on a layer ...........................................................
        if len(path) == 2: 
            layer = result.layers[ path[1] ]
            m = gtk.MenuItem(_("Open Map Window")); menu.append(m); m.show()
            m.connect("activate", lambda w: openMapView(result) )
            
            m = gtk.MenuItem(_("Open Table Window")); menu.append(m); m.show()
            m.connect("activate", lambda w: openTableView(layer) )
            
            m = gtk.SeparatorMenuItem(); menu.append(m); m.show() #----------------

            m = gtk.ImageMenuItem(gtk.STOCK_CUT,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w,l: setClipboardItem(l.copy()), layer)
            m.connect("activate", lambda w,l: l.resultset.remLayer(l), layer)
            
            m = gtk.ImageMenuItem(gtk.STOCK_COPY,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w,l: setClipboardItem(l.copy()), layer)
            
            m = gtk.MenuItem(_("Copy Style")); menu.append(m); m.show()
            m.connect("activate", lambda w,s: setClipboardItem(s.copy()), layer.style)   
            
            # paste operations
            m = gtk.ImageMenuItem(gtk.STOCK_PASTE,accelgroup); menu.append(m); m.show()
            if self.clipboardItem is None:
                #nothing on clipboard -> make unsensitive
                m.set_sensitive(False)
            elif self.clipboardItem.__class__.__name__ == "ResultSet":
                # paste result -> add copy of the item after this layer's result      
                i = self.project.resultsets.index(result)+1
                m.connect("activate", lambda w,r: self.project.insertResultset(i,r.copy()), self.clipboardItem)
            elif self.clipboardItem.__class__.__name__ == "Layer":
                # paste layer -> add layer after this layer
                i = result.layers.index(layer)+1
                m.connect("activate", lambda w,r,l: r.insertLayer(i,l.copy()), result, self.clipboardItem)                   
            else: m.set_sensitive(False)
            
            m = gtk.MenuItem(_("Paste Style")); menu.append(m); m.show()
            m.connect("activate", lambda w,s: setClipboardItem(s.copy()), layer.style) 
            if self.clipboardItem.__class__.__name__ == "LayerStyle":
                m.connect("activate", lambda w,l,s: l.setStyle(s.copy()), layer, self.clipboardItem)                   
            else: m.set_sensitive(False)
                                            
            m = gtk.ImageMenuItem(gtk.STOCK_DELETE,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w,l: l.resultset.remLayer(l), layer)
                                            
            m = gtk.SeparatorMenuItem(); menu.append(m); m.show() #----------------
            
            if layer.isLoading():
                m = gtk.ImageMenuItem(_("Stop Loading")); menu.append(m); m.show()
                img = gtk.Image(); img.set_from_stock(gtk.STOCK_STOP,gtk.ICON_SIZE_MENU); m.set_image( img )
                m.connect("activate", lambda w,l: l.stopLoading(), layer)
            else:
                # reloading a layer is potentially dangerous.
                # run special dialogue to double-check
                m = gtk.ImageMenuItem(_("Reload Layer")); menu.append(m); m.show()
                img = gtk.Image(); img.set_from_stock(gtk.STOCK_REFRESH,gtk.ICON_SIZE_MENU); m.set_image( img )
                m.connect("activate", self.reloadLayerDialog, [layer])
                                    
            m = gtk.ImageMenuItem(gtk.STOCK_PROPERTIES,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w: openLayerProperties(layer) )

        # clicked on a result.......................................................
        elif len(path) == 1: 
            m = gtk.MenuItem(_("Open Map Window")); menu.append(m); m.show()
            m.connect("activate", lambda w: openMapView(result) )
            
            m = gtk.SeparatorMenuItem(); menu.append(m); m.show() #-----------------
            
            m = gtk.ImageMenuItem(gtk.STOCK_CUT,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w,r: setClipboardItem(r.copy()), result)                    
            m.connect("activate", lambda w, r: self.project.remResultset(r), result)
                                
            m = gtk.ImageMenuItem(gtk.STOCK_COPY,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w,r: setClipboardItem(r.copy()), result)                    

            # paste operations
            m = gtk.ImageMenuItem(gtk.STOCK_PASTE,accelgroup); menu.append(m); m.show()
            if self.clipboardItem is None:
                #nothing on clipboard -> make unsensitive
                m.set_sensitive(False)
            elif self.clipboardItem.__class__.__name__ == "ResultSet":
                # paste result -> add copy of the item after this result      
                i = self.project.resultsets.index(result)+1
                m.connect("activate", lambda w,r: self.project.insertResultset(i,r.copy()), self.clipboardItem)
            elif self.clipboardItem.__class__.__name__ == "Layer":
                # paste layer -> add layer to the result
                m.connect("activate", lambda w,r,l: r.addLayer(l.copy()), result, self.clipboardItem)   
            else: m.set_sensitive(False)   
            
            m = gtk.ImageMenuItem(gtk.STOCK_DELETE,accelgroup); menu.append(m); m.show()
            m.connect("activate", lambda w, r: self.project.remResultset(r), result)
            
            m = gtk.SeparatorMenuItem(); menu.append(m); m.show() #----------------
            
            m = gtk.ImageMenuItem(_("Reload Layers")); menu.append(m); m.show()
            img = gtk.Image(); img.set_from_stock(gtk.STOCK_REFRESH,gtk.ICON_SIZE_MENU); m.set_image( img )
            m.connect("activate", self.reloadLayerDialog, result.layers)
            
            m = gtk.ImageMenuItem(gtk.STOCK_PROPERTIES,accelgroup); menu.append(m); m.show()
            m.connect("activate", resultProperties, result)

        #m = gtk.MenuItem(_("Create A New Map")); menu.append(m); m.show()
        #m.connect("activate", lambda w: self.project.addResultset(ResultSet()) )


        menu.popup( None, None, None, event.button, event.time)

    def __onDragReceived(self, treeview, dragContext, x, y, selection, info, eventtime):
        redraw = False
        model, iter_from = treeview.get_selection().get_selected()
        path_from = model.get_path(iter_from)
        
        # find out where we drag from
        result_from = self.project.resultsets[ path_from[0] ]
        if len(path_from) > 1: layer_from = result_from.layers[ path_from[1] ]
        else: layer_from = None

        drop_info = treeview.get_dest_row_at_pos(x, y)

        if drop_info: # find out where we drag to
            path_to, pos = drop_info
            result_to = self.project.resultsets[ path_to[0] ]
            if len(path_to) > 1: layer_to = result_to.layers[ path_to[1] ]
            else: layer_to = None

        else: # drag into whitespace...
            if layer_from is None: #... if result, special case: Move to end of list
                self.project.addResultset(result_from)
            return

        # drag from resultset...
        if layer_from is None and result_from != result_to:

            #... before another resultset
            if layer_to is None and pos == gtk.TREE_VIEW_DROP_BEFORE:
                i = self.project.resultsets.index(result_to)
                self.project.insertResultset(i-1,result_from)

            #... after layer in the list
            elif layer_to == result_to.layers[-1]:
                i = self.project.resultsets.index(result_to)
                self.project.insertResultset(i,result_from)

        # drag from layer...
        elif layer_from is not None and layer_to != layer_from:

            # ... to layer
            if layer_to is not None:
                i = result_to.layers.index(layer_to)
                if pos == gtk.TREE_VIEW_DROP_AFTER or \
                   pos == gtk.TREE_VIEW_DROP_INTO_OR_AFTER: i += 1
                result_to.insertLayer(i,layer_from)

            # ... to result
            else:
                result_to.addLayer(layer_from)


    #def cb_treeEdited(self, cell, pathString, newText ):
        #path = pathString.split(":")
        #result = self.project.resultsets[ int(path[0]) ]
        #it = self.model.get_iter_from_string(pathString)
        #self.model.set_value(it,1,newText)
        #if len(path) == 1: # edited a resultset
            #result.name = newText
        #elif len(path) == 2: # edited a layer's name
            #layer = result.layers[ int(path[1]) ]
            #layer.name = newText


